package cn.dlc.com.filter;

import cn.dlc.com.config.RsaPropertiesConfig;
import cn.dlc.com.pojo.Payload;
import cn.dlc.com.pojo.SysLoginLog;
import cn.dlc.com.pojo.SysUser;
import cn.dlc.com.service.SysLoginLogService;
import cn.dlc.com.utils.JsonUtils;
import cn.dlc.com.utils.JwtUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author deng
 * @date 2021/6/25 11:15
 **/
public class JwtVerifyFilter extends BasicAuthenticationFilter {

    private AuthenticationManager authenticationManager;
    private RsaPropertiesConfig config;

    private SysLoginLogService loginLogService;


    public JwtVerifyFilter(AuthenticationManager authenticationManager, RsaPropertiesConfig config) {
        super(authenticationManager);
        this.config = config;
    }

    public JwtVerifyFilter(AuthenticationManager authenticationManager, RsaPropertiesConfig config,SysLoginLogService loginLogService) {
        super(authenticationManager);
        this.config = config;
        this.loginLogService = loginLogService;
    }

    // 重写认证模块
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        String authorization = request.getHeader("Authorization");
        if(authorization == null || !authorization.startsWith("Bearer ")){
            // 携带的token不正确
            chain.doFilter(request,response);
            // 下面不会执行了，因为有AuthenticationEntryPoint
            try {
                response.setContentType("application/json;charset=UTF-8");
                // 认证失败
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                PrintWriter writer = response.getWriter();

                Map<String,Object> map = new HashMap<>();
                map.put("code",HttpServletResponse.SC_FORBIDDEN);
                map.put("msg","请登录!!!");
                writer.write(JsonUtils.toString(map));
                writer.flush();
                writer.close();

            } catch (Exception e1) {
                e1.printStackTrace();
            }
        } else {
            // token格式正确
            String token = authorization.replace("Bearer ","");
            try {
                Payload<SysUser> payload = JwtUtils.getInfoFromToken(token, config.getPublicKey(), SysUser.class);
                // 获取用户信息
                SysUser userInfo = payload.getUserInfo();
                if(userInfo!= null) {

                    // 增加数据库的逻辑校验，看一下有没有最新的登录，
                    // 判断
                    QueryWrapper<SysLoginLog> wrapper = new QueryWrapper<>();
                    wrapper.ge("username",userInfo.getUsername());
                    wrapper.orderByDesc("login_time");
                    List<SysLoginLog> sysLoginLogs = loginLogService.list(wrapper);
                    if(sysLoginLogs != null && sysLoginLogs.size() > 0) {
                        // 有登录的信息
                        // 获取第一条
                        SysLoginLog sysLoginLog = sysLoginLogs.get(0);
                        if(sysLoginLog.getInvalid() == 0) {
                            // 表示当前用户没有登出，那么可以进入后面的操作
                            // 验证用户，判断是不是这个而用户和角色，密码不需要了，因为登录的时候没有放进去
                            UsernamePasswordAuthenticationToken authResult = new UsernamePasswordAuthenticationToken
                                    (userInfo, null, userInfo.getAuthorities());
                            // 添加到容器里面(为什么第一次登录的时候不放？)
                            SecurityContextHolder.getContext().setAuthentication(authResult);

                            // 放行
                            chain.doFilter(request,response);
                        } else {
                            // 登出了，那么就是失效了
                            // 伪造的，token
                            response.setContentType("application/json;charset=UTF-8");
                            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

                            PrintWriter writer = response.getWriter();

                            Map<String,Object> map = new HashMap<>();
                            map.put("code",HttpServletResponse.SC_FORBIDDEN);
                            map.put("msg","token失效");
                            writer.write(JsonUtils.toString(map));
                            writer.flush();
                            writer.close();
                        }
                    }

                } else {
                    // 伪造的，token
                    System.out.println("token失效");
                }
            } catch (Exception e) {
                System.out.println("token失效");
                // 直接response给用户

                response.setContentType("application/json;charset=UTF-8");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

                PrintWriter writer = response.getWriter();

                Map<String,Object> map = new HashMap<>();
                map.put("code",HttpServletResponse.SC_FORBIDDEN);
                map.put("msg","token失效");
                writer.write(JsonUtils.toString(map));
                writer.flush();
                writer.close();

            }
        }
    }

}
